package main

import (
	"crypto/tls"
	"cybertwin/cybertwin"
	"cybertwin/pb/model"

	"cybertwin/utils/configtools"
	"cybertwin/utils/constants"
	"cybertwin/utils/stringutils"
	"fmt"
	"net"
	"runtime"
	"sync"

	"github.com/panjf2000/gnet/v2"
	log "github.com/sirupsen/logrus"
	"github.com/spf13/viper"
	"google.golang.org/protobuf/proto"
)

func main() {
	port := 8888
	// ip := "127.0.0.1"
	v := viper.New()
	v.AutomaticEnv()
	ctid := v.GetString(constants.CtidEnvKey)
	uid := v.GetString(constants.UidEnvFlag)
	incluster := v.GetBool(configtools.INCLUSTER)
	log.Infof("[cybertwin]-[main]-获取到cybertwin环境变量，ctid=%s, uid=%s, incluster=%v", ctid, uid, incluster)
	ct := &cybertwin.Cybertwin{
		Ctid:    ctid,
		Uid:     uid,
		Network: "tcp",
		Addr:    fmt.Sprintf(":%d", port),

		//Ctid:     "ue_0222b78c-b3ff-4a0f-8dc2-11ee40a36ac5", // 目前我数据库里面存的id是个，我也不知道为啥是ue开头的，凑活用下
		//Uid:      "user_01",
		//UeList:   []string{},
		//UeStatus: []model.UeStatus{},
		//Ip:       fmt.Sprintf("%s:%d", ip, port), // 暂且使用localhost:8888代替
	}
	wg := sync.WaitGroup{}
	wg.Add(2)

	numCPU := runtime.NumCPU() // 获取当前系统的 CPU 核心数量
	fmt.Printf("CPU Cores: %d\n", numCPU)

	// 设置 GOMAXPROCS 变量来限制同时运行的 Goroutine 数量
	// 此处将其设置为 CPU 核心数量的一半，以充分利用多核心，但不占用全部资源
	maxProcs := numCPU / 2
	runtime.GOMAXPROCS(maxProcs)

	ct.Init()

	go runCybertwinServerGnet(ct, &wg) // 使用协程消除gnet.Run带来的阻塞效果
	go runCybertwinTLSServer(port-1, &wg, ct)
	wg.Wait() // 上述两个Run命令在go协程中运行，是非阻塞的，因此我们需要这条命令阻塞主进程
}

// runCybertwinServerGnet 将会运行一个gnet Server，这个server是用来和ue进行交互的
func runCybertwinServerGnet(ct *cybertwin.Cybertwin, wg *sync.WaitGroup) {
	err := gnet.Run(ct, ct.Addr, gnet.WithMulticore(true))
	if err != nil {
		log.Errorln("启动cybertwin失败：", err.Error())
	}
	wg.Done()
}

func runCybertwinTLSServer(port int, wg *sync.WaitGroup, ct *cybertwin.Cybertwin) {
	certFile := "./cybertwin/cert/server.crt"
	keyFile := "./cybertwin/cert/server.key"
	certificate, err := tls.LoadX509KeyPair(certFile, keyFile)
	if err != nil {
		log.Errorf("[runCybertwinTLSServer]-LoadX509KeyPair failed:%s", err.Error())
		wg.Done()
		return
	}
	config := &tls.Config{Certificates: []tls.Certificate{certificate}}
	listen, err := tls.Listen("tcp", fmt.Sprintf("%s:%d", "", port), config)
	if err != nil {
		log.Errorln("[runCybertwinTLSServer]-tls.Listen异常:", err.Error())
		wg.Done()
		return
	} else {
		log.Infof("成功启动tls server: port=%d", port)
	}
	defer listen.Close()
	for {
		conn, err := listen.Accept()
		if err != nil {
			log.Errorln("[runCybertwinTLSServer]-tls.Accept异常:", err.Error())
		} else {
			log.Infof("[runCybertwinTLSServer]-接收到来自%s的请求", conn.RemoteAddr())
		}
		go handle(conn, ct)
	}
	wg.Done()
}

func handle(conn net.Conn, ct *cybertwin.Cybertwin) {
	var data []byte
	data = make([]byte, 1024)
	n, err := conn.Read(data)
	log.Errorf("[runCybertwinTLSServer]-[handle]-读取数据异常, err=%s", err)
	data = data[:n]
	log.Infof("[runCybertwinTLSServer]-读取到消息:%s", string(data))
	// data反序列化一波
	var protoCk2 = &model.PROTO_CK2{}
	err = proto.Unmarshal(data, protoCk2)
	if err != nil {
		log.Errorln("[runCybertwinTLSServer]-无法反序列化数据PROTO_CK2:", err.Error())
		conn.Close()
	}
	// 存储ck2，并且记录ueid为待连接设备
	ct.Ck2 = protoCk2.Ck2
	ct.UeConnectSet[protoCk2.Ueid] = true
	log.Infof("[tls server]-[handle]-成功接收ueid=%s的ck2:%s", stringutils.GetPrefix(protoCk2.Ueid, 9), string(ct.Ck2))
}

// getConfigFromEnv 从环境变量中读取ctid和uid
func getConfigFromEnv() (ctid string, uid string) {
	v := viper.New()
	v.AutomaticEnv()
	ctid = v.GetString("CYBERTWIN_CTID")
	uid = v.GetString("CYBERTWIN_UID")
	return
}
